package br.com.velp.vskygeo.controller;

import br.com.velp.vskygeo.dto.*;
import br.com.velp.vskygeo.service.MysqlService;
import br.com.velp.vskygeo.util.GoogleMapsUtil;
import br.com.velp.vskygeo.util.JsfUtil;
import br.com.velp.vskygeo.util.MensagemUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.primefaces.context.RequestContext;
import org.primefaces.event.TabChangeEvent;
import org.primefaces.event.map.OverlaySelectEvent;
import org.primefaces.event.map.StateChangeEvent;
import org.primefaces.model.map.DefaultMapModel;
import org.primefaces.model.map.LatLng;
import org.primefaces.model.map.MapModel;
import org.primefaces.model.map.Marker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 *
 * @author Eduardo
 */
@Component
public class ControllerBase implements Serializable{
    
    private MapModel mapModel;
    private Rota rota;
    private UltimoDadoLidoResultadoConsultaDTO ultimoDadoLidoSelecionado;
    private List<UltimoDadoLidoResultadoConsultaDTO> ultimosDadosLidos;
    private List<OcorrenciaResultadoConsultaDTO> ocorrencias;
    private List<PontoInteresseResultadoConsultaDTO> pontosInteresse;
    private List<OcorrenciaResultadoConsultaDTO> ocorrenciasAdicionadasMapa;
    private List<Rota> rotas;
    private Double maiorLatitude;
    private Double maiorLongitude;
    private GoogleMapsUtil.GoogleGeoCodeResponse.Results[] resultados;
    private String painelModal;
    private GoogleMapsUtil.GoogleGeoCodeResponse.Results resultEnderecoSelecionado;
    private OcorrenciaResultadoConsultaDTO ocorrenciaSelecionada;
    private InterfaceDTO informacaoSelecionada;
    private int tempoSincronizacao;
    private int zoom;
    private int indiceSelecionado;
    private int tabSelecionada;
    private int indiceOcorrenciaSelecionada;
    private int indiceAmbulanciaSelecionada;
    private int qtdAmbulancias;
    private int qtdOcorrencias;
    private boolean ocorrenciasAlteradas;
    
    @Autowired
    private MysqlService mysqlService;

    public void initialize() {
        
        this.rotas = new ArrayList<Rota>();
        this.rota = new Rota();
        this.ocorrenciasAdicionadasMapa = new ArrayList<OcorrenciaResultadoConsultaDTO>();
        this.tempoSincronizacao = Integer.valueOf(MensagemUtil.getMensagem("principal_tempo_sincronizacao_milisegundos"));
        
        carregarDados();
        
    }
    
    public void carregarDados() {
        
        UsuarioLogadoDTO usuarioLogado = JsfUtil.obterUsuarioLogado();

        this.indiceSelecionado = 0;
        this.indiceOcorrenciaSelecionada = -1;
        this.indiceAmbulanciaSelecionada = -1;
        this.zoom = 8;
        this.maiorLatitude = 0.0;
        this.maiorLongitude = 0.0;
        this.ocorrenciasAlteradas = false;

        this.ultimosDadosLidos = this.mysqlService.recuperarUltimosDadosLidos(usuarioLogado);
        this.ocorrencias = this.mysqlService.recuperarOcorrencias(usuarioLogado);
        this.pontosInteresse = this.mysqlService.obterPontosInteresse(usuarioLogado);
        
        this.qtdAmbulancias = this.ultimosDadosLidos.size();
        this.qtdOcorrencias = this.ocorrencias.size();

        carregarPontosNoMapa(true);

    }
    
    public void atualizarConteudo() {
        
        UsuarioLogadoDTO usuarioLogado = JsfUtil.obterUsuarioLogado();
        
        this.ocorrenciasAlteradas = false;
        this.ultimosDadosLidos = this.mysqlService.recuperarUltimosDadosLidos(usuarioLogado);
        this.ocorrencias = this.mysqlService.recuperarOcorrencias(usuarioLogado);
        this.pontosInteresse = this.mysqlService.obterPontosInteresse(usuarioLogado);
        
        if (this.ocorrencias.size() != this.qtdOcorrencias) {
            this.ocorrenciasAlteradas = true;
        }
        
        this.qtdAmbulancias = this.ultimosDadosLidos.size();
        this.qtdOcorrencias = this.ocorrencias.size();
        
        carregarPontosNoMapa(false);
        
        for (OcorrenciaResultadoConsultaDTO ocorrencia : this.ocorrenciasAdicionadasMapa) {
            
            LatLng latLng = new LatLng(ocorrencia.getLatitude(), ocorrencia.getLongitude());
            
            Marker marker = new Marker(latLng);
            marker.setTitle(obterEnderecoCompleto(ocorrencia));
            marker.setData(this.ocorrenciaSelecionada);
            marker.setIcon(MensagemUtil.getMensagem("principal_img_ocorrencia"));            
            
            this.mapModel.addOverlay(marker);
            
        }
        
    }

    public void carregarPontosNoMapa(boolean alterarLatLng) {

        this.mapModel = new DefaultMapModel();
            
        for (UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido : ultimosDadosLidos) {
            
            Double latitude  = ultimoDadoLido.getLatitude();
            Double longitude = ultimoDadoLido.getLongitude();
            
            if (latitude != null && longitude != null){
                
                LatLng latLong = new LatLng(latitude, longitude);

                Marker marker = new Marker(latLong);
                marker.setId(String.valueOf(ultimoDadoLido.getIdMonitorado()));
                marker.setTitle(ultimoDadoLido.getDescricaoMonitorado());
                marker.setData(ultimoDadoLido);
                marker.setIcon(ControllerPrincipalUtils.obterImagemAmbulanciaMapa(ultimoDadoLido));

                this.mapModel.addOverlay(marker);

                if (alterarLatLng && ultimoDadoLido.getLatitude() < this.maiorLatitude) {
                    this.maiorLatitude = ultimoDadoLido.getLatitude();
                }

                if (alterarLatLng && ultimoDadoLido.getLongitude() < this.maiorLongitude) {
                    this.maiorLongitude = ultimoDadoLido.getLongitude();
                }
                
            }

        }

        for (PontoInteresseResultadoConsultaDTO pontoInteresse : this.pontosInteresse) {
            
            Double latitude  = pontoInteresse.getLatitude();
            Double longitude = pontoInteresse.getLongitude();
            
            LatLng latLong = new LatLng(latitude, longitude);

            Marker marker = new Marker(latLong);
            marker.setTitle(pontoInteresse.getDescricao());
            marker.setData(pontoInteresse);
            marker.setIcon(MensagemUtil.getMensagem("principal_img_marcador"));

            this.mapModel.addOverlay(marker);

        }

    }

    public void selecionarMarcador(OverlaySelectEvent event) {
        
        Marker marcador = (Marker) event.getOverlay();
        this.informacaoSelecionada = (InterfaceDTO) marcador.getData();

    }

    public String obterImagemAmbulancia(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido) {

        return ControllerPrincipalUtils.obterImagemAmbulancia(ultimoDadoLido);

    }

    public String obterTitleImagemAmbulancia(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido) {

        return ControllerPrincipalUtils.obterTitleImagemAmbulancia(ultimoDadoLido);

    }

    public String obterImagemGpsOnOff(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido) {

        return ControllerPrincipalUtils.obterImagemGpsOnOff(ultimoDadoLido);

    }

    public String obterTitleGpsOnOff(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido) {

        return ControllerPrincipalUtils.obterTitleGpsOnOff(ultimoDadoLido);

    }

    public String obterImagemIgnicaoOnOff(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido) {

        return ControllerPrincipalUtils.obterImagemIgnicaoOnOff(ultimoDadoLido);

    }

    public String obterTitleIgnicaoOnOff(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido) {

        return ControllerPrincipalUtils.obterTitleIgnicaoOnOff(ultimoDadoLido);

    }

    public String obterImagemTipoTransmissao(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido) {

        return ControllerPrincipalUtils.obterImagemTipoTransmissao(ultimoDadoLido);

    }

    public String obterTitleTipoTransmissao(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido) {

        return ControllerPrincipalUtils.obterTitleTipoTransmissao(ultimoDadoLido);

    }

    public void centralizarAmbulanciaSelecionada(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLido, int indexTab) {

        this.zoom = 20;

        this.maiorLatitude = ultimoDadoLido.getLatitude();
        this.maiorLongitude = ultimoDadoLido.getLongitude();

    }

    public void centralizarPontoInteresseSelecionado(PontoInteresseResultadoConsultaDTO pontoInteresse) {

        this.zoom = 20;

        this.maiorLatitude = pontoInteresse.getLatitude();
        this.maiorLongitude = pontoInteresse.getLongitude();

    }

    public void visualizarOcorrenciaNoMapa(OcorrenciaResultadoConsultaDTO ocorrencia, int index) {
        
        this.indiceSelecionado = index;
        this.ocorrenciaSelecionada = ocorrencia;
        
        ControllerAdicionarPontosInteresse controllerAddPontosInteresse = (ControllerAdicionarPontosInteresse) JsfUtil.getSpringBean("controllerAddPontosInteresse");
        controllerAddPontosInteresse.setResultadosPesquisa(null);
        controllerAddPontosInteresse.setOcorrencia(ocorrencia);
        controllerAddPontosInteresse.setParamPesquisa(obterEnderecoCompleto(ocorrencia));
        controllerAddPontosInteresse.pesquisarEnderecos();
        
        RequestContext.getCurrentInstance().execute("pn_pesquisa_enderecos.show();");

    }

    public String obterEnderecoCompleto(OcorrenciaResultadoConsultaDTO ocorrencia) {

        StringBuilder endereco = new StringBuilder();

        if (StringUtils.isNotBlank(ocorrencia.getLogradouro())) {
            endereco.append(ocorrencia.getLogradouro());
        }
        
        if (ocorrencia.getNumeroLogradouro() != 0) {
            if (!endereco.toString().isEmpty()) {
                endereco.append(", ");
            }
            endereco.append(ocorrencia.getNumeroLogradouro());
        }

        if (StringUtils.isNotBlank(ocorrencia.getCidade())) {
            if (!endereco.toString().isEmpty()) {
                endereco.append(", ");
            }
            endereco.append(ocorrencia.getCidade());
        }
        
        if (StringUtils.isNotBlank(ocorrencia.getUf())) {
            if (!endereco.toString().isEmpty()) {
                endereco.append(", ");
            }
            endereco.append(ocorrencia.getUf());
        }
        
        endereco.append(", Brasil");

        return endereco.toString();

    }

    public void adicionarMarcadorOcorrencia(GoogleMapsUtil.GoogleGeoCodeResponse.Results result) {

        String info = result.getFormatted_address();
        Double latitude = Double.valueOf(result.getGeometry().getLocation().getLat());
        Double longitude = Double.valueOf(result.getGeometry().getLocation().getLng());
        
        this.ocorrenciaSelecionada.setLatitude(latitude);
        this.ocorrenciaSelecionada.setLongitude(longitude);

        LatLng latLong = new LatLng(latitude, longitude);

        Marker marker = new Marker(latLong);
        marker.setTitle(info);
        marker.setData(this.ocorrenciaSelecionada);
        marker.setIcon(MensagemUtil.getMensagem("principal_img_ocorrencia"));
        
        this.zoom = 13;
        this.maiorLatitude = latitude;
        this.maiorLongitude = longitude;
        this.mapModel.addOverlay(marker);
        
        this.ocorrenciasAdicionadasMapa.add(this.ocorrenciaSelecionada);

    }
    
    public void removerOcorrenciaSelecionada(OcorrenciaResultadoConsultaDTO ocorrencia, int index) {
        
        this.indiceSelecionado = index;
        this.ocorrenciaSelecionada = ocorrencia;
        this.ocorrenciaSelecionada.setLatitude(0);
        this.ocorrenciaSelecionada.setLongitude(0);
        
        Iterator<Marker> marcadores = this.mapModel.getMarkers().iterator();
        
        while (marcadores.hasNext()) {
            Marker marcador = marcadores.next();
            if (marcador.getData().equals(ocorrencia)) {
                marcadores.remove();
                this.ocorrenciasAdicionadasMapa.remove(ocorrencia);
            }
        }
        
    }
    
    public void centralizarOcorrenciaSelecionada(OcorrenciaResultadoConsultaDTO ocorrencia, int indexTab) {
        
        if (ocorrencia == null 
                || ocorrencia.getLatitude() == 0 
                || ocorrencia.getLongitude() == 0){
            return;
        }
        
        this.zoom = 13;
        this.maiorLatitude = ocorrencia.getLatitude();
        this.maiorLongitude = ocorrencia.getLongitude();
        
    }
    
    public boolean isOcorrenciaVisualizada() {
        
        return this.ocorrenciaSelecionada != null && this.ocorrenciasAdicionadasMapa.contains(this.ocorrenciaSelecionada);
        
    }
    
    public String obterImagemAlerta(OcorrenciaResultadoConsultaDTO ocorrencia) {
        
        return ControllerPrincipalUtils.obterImagemAlerta(ocorrencia);
        
    }
    
    public void montarRota(OcorrenciaResultadoConsultaDTO ocorrencia) {
        
        this.rota = new Rota();
        UltimoDadoLidoResultadoConsultaDTO dadoLido = obterUltimoDadoLido(ocorrencia.getIdMonitorado());
        
        this.rota.setOcorrencia(ocorrencia);
        this.rota.setLatitudeOrigem(ocorrencia.getLatitude());
        this.rota.setLongitudeOrigem(ocorrencia.getLongitude());
        this.rota.setLatitudeDestino(dadoLido.getLatitude());
        this.rota.setLongitudeDestino(dadoLido.getLongitude());
        
        this.rotas.add(this.rota);
        
        RequestContext.getCurrentInstance().execute("pn_visualizar_rota.show();");
        
    }
    
    public UltimoDadoLidoResultadoConsultaDTO obterUltimoDadoLido(Integer idMonitorado) {
        for (UltimoDadoLidoResultadoConsultaDTO value : this.ultimosDadosLidos) {
            if (value.getIdMonitorado() == idMonitorado){
                return value;
            }
        }
        return null;
    }
    
    public void capturarTabSelecionada(TabChangeEvent event) {
        
        String tabSelecionada = event.getTab().getTitle();
        
        if (MensagemUtil.getMensagem("principal_ambulancias").equals(tabSelecionada)){
            this.tabSelecionada = 0;
        } else if (MensagemUtil.getMensagem("principal_ocorrencias").equals(tabSelecionada)) {
            this.tabSelecionada = 1;            
        } else {
            this.tabSelecionada = 2;
        }
        
    } 
    
    public void onStateChange(StateChangeEvent event) {
        
        this.maiorLatitude = event.getCenter().getLat();
        this.maiorLongitude = event.getCenter().getLng();
        this.zoom = event.getZoomLevel();
        
    }
    
    // <editor-fold desc="GETTERS AND SETTERS" defaultstate="collapsed">            
    public MapModel getMapModel() {
        return mapModel;
    }

    public void setMapModel(MapModel mapModel) {
        this.mapModel = mapModel;
    }

    public List<UltimoDadoLidoResultadoConsultaDTO> getUltimosDadosLidos() {
        return ultimosDadosLidos;
    }

    public void setUltimosDadosLidos(List<UltimoDadoLidoResultadoConsultaDTO> ultimosDadosLidos) {
        this.ultimosDadosLidos = ultimosDadosLidos;
    }

    public UltimoDadoLidoResultadoConsultaDTO getUltimoDadoLidoSelecionado() {
        return ultimoDadoLidoSelecionado;
    }

    public void setUltimoDadoLidoSelecionado(UltimoDadoLidoResultadoConsultaDTO ultimoDadoLidoSelecionado) {
        this.ultimoDadoLidoSelecionado = ultimoDadoLidoSelecionado;
    }

    public String getMaiorLatLong() {
        if (this.maiorLatitude == null || this.maiorLongitude == null) {
            return null;
        }
        return this.maiorLatitude.toString().concat(",").concat(this.maiorLongitude.toString());
    }

    public int getTempoSincronizacao() {
        return tempoSincronizacao;
    }

    public void setTempoSincronizacao(int tempoSincronizacao) {
        this.tempoSincronizacao = tempoSincronizacao;
    }

    public int getZoom() {
        return zoom;
    }

    public void setZoom(int zoom) {
        this.zoom = zoom;
    }

    public List<OcorrenciaResultadoConsultaDTO> getOcorrencias() {
        return ocorrencias;
    }

    public void setOcorrencias(List<OcorrenciaResultadoConsultaDTO> ocorrencias) {
        this.ocorrencias = ocorrencias;
    }

    public List<PontoInteresseResultadoConsultaDTO> getPontosInteresse() {
        return pontosInteresse;
    }

    public void setPontosInteresse(List<PontoInteresseResultadoConsultaDTO> pontosInteresse) {
        this.pontosInteresse = pontosInteresse;
    }

    public String getPainelModal() {
        return painelModal;
    }

    public void setPainelModal(String painelModal) {
        this.painelModal = painelModal;
    }

    public GoogleMapsUtil.GoogleGeoCodeResponse.Results[] getResultados() {
        return resultados;
    }

    public void setResultados(GoogleMapsUtil.GoogleGeoCodeResponse.Results[] resultados) {
        this.resultados = resultados;
    }

    public OcorrenciaResultadoConsultaDTO getOcorrenciaSelecionada() {
        return ocorrenciaSelecionada;
    }

    public void setOcorrenciaSelecionada(OcorrenciaResultadoConsultaDTO ocorrenciaSelecionada) {
        this.ocorrenciaSelecionada = ocorrenciaSelecionada;
    }

    public GoogleMapsUtil.GoogleGeoCodeResponse.Results getResultEnderecoSelecionado() {
        return resultEnderecoSelecionado;
    }

    public void setResultEnderecoSelecionado(GoogleMapsUtil.GoogleGeoCodeResponse.Results resultEnderecoSelecionado) {
        this.resultEnderecoSelecionado = resultEnderecoSelecionado;
    }
    
    public List<OcorrenciaResultadoConsultaDTO> getOcorrenciasAdicionadasMapa() {
        return ocorrenciasAdicionadasMapa;
    }

    public void setOcorrenciasAdicionadasMapa(List<OcorrenciaResultadoConsultaDTO> ocorrenciasAdicionadasMapa) {
        this.ocorrenciasAdicionadasMapa = ocorrenciasAdicionadasMapa;
    }
    
    public int getIndiceSelecionado() {
        return indiceSelecionado;
    }

    public void setIndiceSelecionado(int indiceSelecionado) {
        this.indiceSelecionado = indiceSelecionado;
    }
    
    public InterfaceDTO getInformacaoSelecionada() {
        return informacaoSelecionada;
    }

    public void setInformacaoSelecionada(InterfaceDTO informacaoSelecionada) {
        this.informacaoSelecionada = informacaoSelecionada;
    }

    public List<Rota> getRotas() {
        return rotas;
    }

    public void setRotas(List<Rota> rotas) {
        this.rotas = rotas;
    }

    public Rota getRota() {
        return rota;
    }

    public void setRota(Rota rota) {
        this.rota = rota;
    }
    
    public UsuarioLogadoDTO getUsuarioLogado() {
        return (UsuarioLogadoDTO) JsfUtil.recuperarObjetoSessao("usuarioLogado");
    }

    public int getTabSelecionada() {
        return tabSelecionada;
    }

    public void setTabSelecionada(int tabSelecionada) {
        this.tabSelecionada = tabSelecionada;
    }
    
    public int getIndiceOcorrenciaSelecionada() {
        return indiceOcorrenciaSelecionada;
    }

    public void setIndiceOcorrenciaSelecionada(int indiceOcorrenciaSelecionada) {
        this.indiceOcorrenciaSelecionada = indiceOcorrenciaSelecionada;
    }

    public int getIndiceAmbulanciaSelecionada() {
        return indiceAmbulanciaSelecionada;
    }

    public void setIndiceAmbulanciaSelecionada(int indiceAmbulanciaSelecionada) {
        this.indiceAmbulanciaSelecionada = indiceAmbulanciaSelecionada;
    }
    
    public int getQtdAmbulancias() {
        return qtdAmbulancias;
    }

    public void setQtdAmbulancias(int qtdAmbulancias) {
        this.qtdAmbulancias = qtdAmbulancias;
    }

    public int getQtdOcorrencias() {
        return qtdOcorrencias;
    }

    public void setQtdOcorrencias(int qtdOcorrencias) {
        this.qtdOcorrencias = qtdOcorrencias;
    }
    
    public boolean isOcorrenciasAlteradas() {
        return ocorrenciasAlteradas;
    }

    public void setOcorrenciasAlteradas(boolean ocorrenciasAlteradas) {
        this.ocorrenciasAlteradas = ocorrenciasAlteradas;
    }
    // </editor-fold>          
    
}
